/**
 * 
 */
package net.hvacapp.cmvrfforandroid.http;

import java.io.File;
import java.io.IOException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import android.text.TextUtils;
import android.util.Log;

import com.alibaba.fastjson.JSON;

import com.squareup.okhttp.Callback;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;

import net.hvacapp.cmvrfforandroid.AppException;
import net.hvacapp.cmvrfforandroid.utils.UrlUtils;

/**
 * OKhttp基类
 * 
 * @author hailong.han
 * @description 2014年9月5日
 * 
 */
public class BasicHttpClient {
	private final static String TAG = "BaseHttpClient";

	private final static int TIMEOUT_CONNECTION = 10;// 超时连接时间
	private final static int TIMEOUT_READ = 30; // 读超时
	private final static int TIMEOUT_WRITE = 10;// 写超时

	private final static String MEDIA_JSON = "application/json";

	public static final MediaType MEDIA_TYPE_JSON = MediaType
			.parse("application/json; charset=utf-8");

	public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType
			.parse("text/x-markdown; charset=utf-8");

	/**
	 * 获取Cookie管理器
	 * 
	 * @return
	 */
	private static CookieManager getCookieManager() {
		CookieManager cookieManager = new CookieManager();
		cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
		CookieHandler.setDefault(cookieManager);
		return cookieManager;
	}

	/**
	 * 获取okhttpclient
	 * 
	 * @return
	 */
	public static OkHttpClient getHttpClient() {
		OkHttpClient okHttpClient = new OkHttpClient();

		okHttpClient.setConnectTimeout(TIMEOUT_CONNECTION, TimeUnit.SECONDS);
		okHttpClient.setReadTimeout(TIMEOUT_READ, TimeUnit.SECONDS);
		okHttpClient.setWriteTimeout(TIMEOUT_WRITE, TimeUnit.SECONDS);
		okHttpClient.setFollowSslRedirects(true);
		okHttpClient.setCookieHandler(getCookieManager());

		return okHttpClient;
	}

	/**
	 * 同步 http get请求基类
	 * 
	 * @param url
	 * @return
	 * @throws AppException
	 */
	public static String httpGet(String url) throws AppException {
		String result = "";

		OkHttpClient okHttpClient = getHttpClient();

		Request request = new Request.Builder().url(url).get()
				.header("Accept", MEDIA_JSON)
				.addHeader("Content-Type", MEDIA_JSON).build();

		try {
			Response response = okHttpClient.newCall(request).execute();

			if (response.isSuccessful()) {
				result = response.body().string();
				
//				UIHelper.handleErrorCode(result);
				
			} else {
				throw AppException.http(response.code());
			}

		} catch (IOException e) {
			Log.e(TAG, e.toString());
			throw AppException.network(e);
		}

		return result;
	}

	/**
	 * 异步的http get请求
	 * 
	 * @param <T>
	 * @param url
	 * @param callback
	 */
	public static <T> void httpGetAsync(String url, Callback callback) {
		OkHttpClient okHttpClient = getHttpClient();
		Request request = new Request.Builder().url(url).get()
				.header("Accept", MEDIA_JSON)
				.addHeader("Content-Type", MEDIA_JSON).build();
		okHttpClient.newCall(request).enqueue(callback);
	}

	/**
	 * 同步 HTTP POST基类
	 * 
	 * @param url
	 * @param params
	 * @return
	 * @throws AppException
	 */
	public static String httpPost(String url, String params)
			throws AppException {
		String result = "";
		OkHttpClient okHttpClient = getHttpClient();
		Request request = new Request.Builder().url(url)
				.post(RequestBody.create(MEDIA_TYPE_JSON, params))
				.header("Accept", MEDIA_JSON)
				.addHeader("Content-Type", MEDIA_JSON).build();

		try {
			Response response = okHttpClient.newCall(request).execute();

			if (response.isSuccessful()) {
				result = response.body().string();
//				UIHelper.handleErrorCode(result);
			} else {
				throw AppException.http(response.code());
			}

		} catch (IOException e) {
			Log.e(TAG, e.toString());
			throw AppException.network(e);
		}

		return result;
	}

	/**
	 * 异步 POST 请求基类
	 * 
	 * @param url
	 * @param params
	 * @param callback
	 * @param callback
	 */
	public static <T> void httpPostAsync(String url, String params,
			Callback callback) {

		OkHttpClient okHttpClient = getHttpClient();
		Request request = new Request.Builder().url(url)
				.post(RequestBody.create(MEDIA_TYPE_JSON, params))
				.header("Accept", MEDIA_JSON)
				.addHeader("Content-Type", MEDIA_JSON).build();

		okHttpClient.newCall(request).enqueue(callback);
	}

	/**
	 * ========================================================================
	 * ===============================
	 **/

	/**
	 * 通过url和tk字符串请求服务器
	 * 
	 * @param url
	 * @param tkString
	 * @return
	 * @throws AppException
	 */
	public static String httpGet(String url, String tkString)
			throws AppException {
		String result = "";

		Map<String, Object> param = new HashMap<String, Object>();
		param.put("tk", tkString);
		result = httpGet(url, param);

		return result;
	}

	/**
	 * 带参数的Get请求
	 * 
	 * @param url
	 * @param params
	 * @return
	 * @throws AppException
	 */
	public static String httpGet(String url, Map<String, Object> params)
			throws AppException {
		String result = "";

		String netUrl = makeGetUrl(url, params);
		netUrl = UrlUtils.urlConvert(netUrl);
		result = httpGet(netUrl);

		return result;
	}

	/**
	 * 异步的，通过url和tk字符串请求服务器
	 * 
	 * @param url
	 * @param tkString
	 * @return
	 * @return
	 * @throws AppException
	 */
	public static <T> void httpGetAsync(String url, String tkString,
			Callback callback) {
		Map<String, Object> param = new HashMap<String, Object>();
		param.put("tk", tkString);
		httpGetAsync(url, param, callback);
	}
	
	/**
	 * @param url
	 * @param tk
	 * @param params
	 * @param callback
	 */
	public static <T> void httpGetAsync(String url,String tk,Map<String, Object> params,Callback callback){
		Map<String, Object> httpParams = new HashMap<String, Object>();
		httpParams.put("tk", tk);
		httpParams.putAll(params);
		httpGetAsync(url, httpParams, callback);
	}
	
	/**
	 * 带参数的http get异步请求 建议不要操作耗时操作
	 * 
	 * @param url
	 * @param params
	 * @param callback
	 */
	public static <T> void httpGetAsync(String url, Map<String, Object> params,
			Callback callback) {
		String netUrl = makeGetUrl(url, params);
		netUrl = netUrl.replaceAll("\n", "");
		httpGetAsync(netUrl, callback);
	}

	/**
	 * 同步 Get 不带参数
	 * 
	 * @param url
	 * @param c
	 * @return
	 * @throws AppException
	 */
	public static <T> T httpGet(String url, Class<T> c) throws AppException {
		String json = httpGet(url);
		T t = JSON.parseObject(json, c);
		return t;
	}

	/**
	 * 同步 Get 带有参数的
	 * 
	 * @param url
	 * @param params
	 * @param c
	 * @return
	 * @throws AppException
	 */
	public static <T> T httpGet(String url, Map<String, Object> params,
			Class<T> c) throws AppException {
		String netUrl = makeGetUrl(url, params);
		String json = httpGet(netUrl);
		T t = JSON.parseObject(json, c);
		return t;
	}

	/**
	 * http post请求
	 * @param url
	 * @param tk
	 * @param jsonStr
	 * @return
	 * @throws AppException
	 */
	public static String httpPost(String url, String tk, String jsonStr)
			throws AppException {
		String result = "";
		String realUrl = url;
		if (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(tk)) {
			realUrl += "?tk=";
			realUrl += tk;
		}

		result = httpPost(realUrl, jsonStr);

		return result;
	}

	/**
	 * 同步 POST 请求
	 * 
	 * @param url
	 * @param params
	 * @return
	 * @throws AppException
	 */
	public static String httpPost(String url, Map<String, Object> params)
			throws AppException {
		String result = "";

		String strParams = "";
		if (params != null) {
			strParams = JSON.toJSONString(params);
		}

		result = httpPost(url, strParams);

		return result;
	}

	/**
	 * 同步 POST
	 * 
	 * @param url
	 * @param params
	 * @param c
	 * @return
	 * @throws AppException
	 */
	public static <T> T httpPost(String url, Map<String, Object> params,
			Class<T> c) throws AppException {
		String json = httpPost(url, params);
		T t = JSON.parseObject(json, c);
		return t;
	}

	/**
	 * 异步 POST
	 * @param url
	 * @param params
	 * @param callback
	 * @param <T>
	 */
	public static <T> void httpPostAsync(String url,
			Map<String, Object> params, Callback callback) {
		String strParams = "";
		if (params != null) {
			strParams = JSON.toJSONString(params);
		}

		httpPostAsync(url, strParams, callback);
	}

	/**
	 * 异步请求 POST 带参数tk
	 * 
	 * @param url
	 * @param tk
	 * @param params
	 * @param callback
	 */
	public static void httpPostAsync(String url, String tk,
			Map<String, Object> params, Callback callback) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("tk", tk);
		String netUrl = makeGetUrl(url, map);
		httpPostAsync(netUrl, params, callback);
	}

	/**
	 * 异步 POST 带参数tk 参数格式Json
	 * 
	 * @param url
	 * @param tk
	 * @param json
	 * @param callback
	 */
	public static void httpPostAsync(String url, String tk, String json,
			Callback callback) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("tk", tk);
		String netUrl = makeGetUrl(url, map);
		httpPostAsync(netUrl, json, callback);
	}

	/**
	 * 多参数、多文件上传
	 * 
	 * @param url
	 * @param params
	 * @param files
	 * @return
	 * @throws AppException
	 */
	public static String httpPost(String url, Map<String, Object> params,
			List<Map<String, File>> files) throws AppException {
		String result = "";

		OkHttpClient okHttpClient = getHttpClient();

		MultipartBuilder multipartBuilder = new MultipartBuilder();
		multipartBuilder.type(MultipartBuilder.FORM);

		String strParams = "";
		if (params != null) {
			strParams = JSON.toJSONString(params);
		}

		if (!TextUtils.isEmpty(strParams)) {
			multipartBuilder.addPart(RequestBody.create(MEDIA_TYPE_JSON,
					strParams));
		}

		if (files != null) {
			for (Map<String, File> map : files) {
				Iterator<Entry<String, File>> iterator = map.entrySet()
						.iterator();
				if (iterator.hasNext()) {
					Entry<String, File> entry = iterator.next();
					File file = entry.getValue();
					if (file.exists()) {
						multipartBuilder.addPart(RequestBody.create(
								MEDIA_TYPE_MARKDOWN, file));
					}
				}
			}
		}

		RequestBody requestBody = multipartBuilder.build();

		Request request = new Request.Builder().url(url).post(requestBody)
				.build();

		try {
			Response response = okHttpClient.newCall(request).execute();

			if (response.isSuccessful()) {
				result = response.body().string();
			} else {
				throw AppException.http(response.code());
			}

		} catch (IOException e) {
			Log.e(TAG, e.toString());
			throw AppException.network(e);
		}

		return result;
	}

	/**
	 * Get请求根据参数生成URL
	 * 
	 * @param url
	 * @param params
	 * @return
	 */
	public static String makeGetUrl(String url, Map<String, Object> params) {
		StringBuilder sb = new StringBuilder(url);
		if (sb.indexOf("?") < 0) {
			sb.append('?');
		}
		for (String key : params.keySet()) {
			sb.append('&');
			sb.append(key);
			sb.append('=');
			sb.append(params.get(key));
		}
		return sb.toString().replace("?&", "?");
	}

	/**
	 * 异步 PUT 请求基类
	 *
	 * @param url
	 * @param params
	 * @param callback
	 * @param callback
	 */
	public static <T> void httpPutAsync(String url, Map<String, Object> params,
										 Callback callback) {

		OkHttpClient okHttpClient = getHttpClient();
		String strParams = "";
		if (params != null) {
			strParams = JSON.toJSONString(params);
		}
		Request request = new Request.Builder().url(url)
				.put(RequestBody.create(MEDIA_TYPE_JSON, strParams))
				.header("Accept", MEDIA_JSON)
				.addHeader("Content-Type", MEDIA_JSON).build();

		okHttpClient.newCall(request).enqueue(callback);
	}

	/**
	 * 异步请求 POST 带参数tk
	 *
	 * @param url
	 * @param tk
	 * @param params
	 * @param callback
	 */
	public static void httpPutAsync(String url, String tk,
									 Map<String, Object> params, Callback callback) {
		String realUrl = url;
		if (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(tk)) {
			realUrl += "?tk=";
			realUrl += tk;
		}
		httpPutAsync(realUrl, params, callback);
	}


	/**
	 * 异步 Delete 请求基类
	 *
	 * @param url
	 * @param params
	 * @param callback
	 * @param callback
	 */
	public static <T> void httpDeleteAsync(String url, Map<String, Object> params,
										Callback callback) {

		OkHttpClient okHttpClient = getHttpClient();
		String newUrl = makeGetUrl(url, params);
		Request request = new Request.Builder().url(newUrl)
				.delete()
				.header("Accept", MEDIA_JSON)
				.addHeader("Content-Type", MEDIA_JSON).build();

		okHttpClient.newCall(request).enqueue(callback);
	}

	/**
	 * 异步请求 POST 带参数tk
	 *
	 * @param url
	 * @param tk
	 * @param params
	 * @param callback
	 */
	public static void httpDeleteAsync(String url, String tk,
									Map<String, Object> params, Callback callback) {
		String realUrl = url;
		if (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(tk)) {
			realUrl += "?tk=";
			realUrl += tk;
		}
		httpDeleteAsync(realUrl, params, callback);
	}

	/**
	 * 多文件上传(异步)
	 * @param url
	 * @param files
	 * @param callback
	 * @throws AppException
	 */
	public static void httpPostFilesAsync(final String url, List<File> files, String mediaType, final Callback callback) {
		final OkHttpClient okHttpClient = getHttpClient();

		MultipartBuilder multipartBuilder = new MultipartBuilder();
		multipartBuilder.type(MultipartBuilder.FORM);
		if (files != null) {
			for (File file : files) {
				if (file.exists()) {
					Headers headers = new Headers.Builder()
							.add("Content-Disposition", "form-data; name=\"image\"; filename=\"" + file.getName() + "\"")
							.build();
					multipartBuilder.addPart(headers, RequestBody.create(MediaType.parse(mediaType), file));
				}
			}
		}
		final RequestBody requestBody = multipartBuilder.build();

		Request request = new Request.Builder()
				.url(url)
				.post(requestBody)
				.build();

		okHttpClient.newCall(request).enqueue(callback);
	}

}
